/*
 * Copyright (C) 2023 Realtek Semiconductor Corp.
 * All Rights Reserved.
 *
 * This program is the proprietary software of Realtek Semiconductor
 * Corporation and/or its licensors, and only be used, duplicated,
 * modified or distributed under the authorized license from Realtek.
 *
 * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
 * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 *
 * Purpose : Definition of ME handler: PPTP FTTR P2MP Port   (65506)
 *
 * Feature : The file includes the following modules and sub-modules
 *           (1) ME handler: PPTP FTTR P2MP Port   (65506)
 */

#include "app_basic.h"
#include "omci_task.h"
#include "feature_mgmt.h"

MIB_TABLE_INFO_T gMibPptpFttrP2mpPortTableInfo;
MIB_ATTR_INFO_T  gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ATTR_NUM];
MIB_TABLE_PPTP_FTTR_P2MP_PORT_T gMibPortFttrP2mpPortDefRow;
MIB_TABLE_OPER_T gMibPptpFttrP2mpPortOper;

static GOS_ERROR_CODE omci_mib_pptp_fttr_p2mp_port_reset(UINT32 args_num, ...)
{

    INT32 mfuPortId;
    MIB_TABLE_PPTP_FTTR_P2MP_PORT_T mibPptpFttrP2mpPort;

    MIB_Default(MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX, &mibPptpFttrP2mpPort, sizeof(MIB_TABLE_PPTP_FTTR_P2MP_PORT_T));

    for(mfuPortId = 0; mfuPortId < FTTR_P2MP_MFU_POT_NUM;mfuPortId++)
    {
        mibPptpFttrP2mpPort.EntityID         = (UINT16)(mfuPortId);
        OMCI_LOG(OMCI_LOG_LEVEL_INFO, "Resetting MIB: PPTP FTTR P2MP PORT EntityID:0x%04x", mibPptpFttrP2mpPort.EntityID);

        GOS_ASSERT(GOS_OK == MIB_Set(MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX, &mibPptpFttrP2mpPort, sizeof(MIB_TABLE_PPTP_FTTR_P2MP_PORT_T)));
        OMCI_MeOperCfg(MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX, NULL, &mibPptpFttrP2mpPort, MIB_ADD,
            omci_GetOltAccAttrSet(MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX, OMCI_ME_ATTR_ACCESS_SBC), OMCI_MSG_BASELINE_PRI_LOW);

    }

    return GOS_OK;
 
}

GOS_ERROR_CODE omci_mib_pptp_fttr_p2mp_port_drv_cfg(void              *pOldRow,
                            void            *pNewRow,
                            MIB_OPERA_TYPE  operationType,
                            MIB_ATTRS_SET   attrSet,
                            UINT32          pri)
{
    GOS_ERROR_CODE      ret = GOS_OK;
    MIB_TABLE_INDEX     tableIndex = MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX;

    switch (operationType)
    {     
        case MIB_ADD:
            ret = mib_alarm_table_add(tableIndex, pNewRow);
            break;
        case MIB_DEL:
            ret = mib_alarm_table_del(tableIndex, pOldRow);
            break;
        default:
            break;
    }
    return ret;    
}

static GOS_ERROR_CODE omci_mib_pptp_fttr_p2mp_port_alarm_handler(MIB_TABLE_INDEX  tableIndex,
                                            omci_alm_data_t     alarmData,
                                            omci_me_instance_t  *pInstanceID,
                                            BOOL                *pIsUpdated)
{
    mib_alarm_table_t	alarmTable;
    BOOL                isSuppressed;

    if (!pInstanceID || !pIsUpdated)
        return GOS_ERR_PARAM;

    *pIsUpdated = FALSE;

    // extract instanceID from alarm detail
    *pInstanceID = alarmData.almDetail;

    if (GOS_OK != mib_alarm_table_get(tableIndex, *pInstanceID, &alarmTable))
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "Get alarm table fail: %s, 0x%x",
            MIB_GetTableName(tableIndex), *pInstanceID);

        return GOS_FAIL;
    }

    // update alarm status if it has being changed
    mib_alarm_table_update(&alarmTable, &alarmData, pIsUpdated);

    if (*pIsUpdated)
    {
        if (GOS_OK != mib_alarm_table_set(tableIndex, *pInstanceID, &alarmTable))
        {
            OMCI_LOG(OMCI_LOG_LEVEL_ERR, "Set alarm table fail: %s, 0x%x",
            MIB_GetTableName(tableIndex), *pInstanceID);
            
            return GOS_FAIL;
        }
        
    // check if notifications are suppressed by parent's admin state
    omci_is_notify_suppressed_by_circuitpack(0xFF, &isSuppressed);

    if (isSuppressed)
        *pIsUpdated = FALSE;

    }

    return GOS_OK;
}


static GOS_ERROR_CODE pptp_fttr_p2mp_port_test_handler(void    *pData)
{
    GOS_ERROR_CODE                      ret = GOS_OK;
    omci_msg_norm_t                     *pOmciMsg;
    MIB_TABLE_INDEX                     tableIndex = MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX;
    UINT16                              tempBuf;
    omci_dm_fttr_optical_info_t         dmFttrOpticalInfo;

    // make sure the data is available
    if (!pData)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "Test data unavailable to proceed: %s",
            MIB_GetTableName(tableIndex));

        return GOS_ERR_PARAM;
    }
    pOmciMsg = (omci_msg_norm_t *)pData;

    if(pOmciMsg->devId == OMCI_MSG_EXTENDED_DEVICE_ID)
    {
        pOmciMsg->contentLength = OMCI_MSG_EXTENDED_PP2P_FTTR_P2MP_PORT_RESULT_RSP_LENGTH;
    }

    // fill in header
    pOmciMsg->db     = 0;
    pOmciMsg->ar     = 0;
    pOmciMsg->ak     = 0;
    pOmciMsg->type   = OMCI_MSG_TYPE_TEST_RESULT;

    memset(&dmFttrOpticalInfo, 0, sizeof(omci_dm_fttr_optical_info_t));
    dmFttrOpticalInfo.devType = OMCI_DM_FTTR_DEVICE_TYPE_MFU;


    if(FAL_OK == feature_api(FEATURE_API_FTTR_P2MP_GET, 
                        OMCI_DM_FTTR_CMD_GET_OPTICAL_INFO, 
                        &dmFttrOpticalInfo, 
                        sizeof(omci_dm_fttr_optical_info_t)))
    {

       // unit: V, 20 mV resolution
       tempBuf = GOS_Htons(dmFttrOpticalInfo.Voltage / 200);
       memcpy(&pOmciMsg->content[1], &tempBuf, sizeof(UINT16));
       pOmciMsg->content[0] = PPTP_FTTR_P2MP_PORT_TEST_SELF_TEST_RESULT_POWER_FEED_VOLTAGE;

       // unit: dBu (dBm = 10*log(mW), dBu = 10*log(mw*10^3) = dBm+30), 0.002 dB resolution
       tempBuf = GOS_Htons((dmFttrOpticalInfo.rxPower + 30) * 500);
       memcpy(&pOmciMsg->content[4], &tempBuf, sizeof(UINT16));
       pOmciMsg->content[3] = PPTP_FTTR_P2MP_PORT_TEST_SELF_TEST_RESULT_RX_OPTICAL_POWER;

       // unit: dBu (dBm = 10*log(mW), dBu = 10*log(mw*10^3) = dBm+30), 0.002 dB resolution
       tempBuf = GOS_Htons((dmFttrOpticalInfo.txPower + 30) * 500);
       memcpy(&pOmciMsg->content[7], &tempBuf, sizeof(UINT16));
       pOmciMsg->content[6] = PPTP_FTTR_P2MP_PORT_TEST_SELF_TEST_RESULT_MEAN_OPTICAL_POWER;

        // unit: mA, 2 uA resolution
        tempBuf = GOS_Htons(dmFttrOpticalInfo.baisCurrent);
        memcpy(&pOmciMsg->content[10], &tempBuf, sizeof(UINT16));
        pOmciMsg->content[9] = PPTP_FTTR_P2MP_PORT_TEST_SELF_TEST_RESULT_LASER_BIAS_CURRENT;

        // unit: degrees (C), 1/256 resolution
        tempBuf = GOS_Htons(dmFttrOpticalInfo.temperature * 256);
        memcpy(&pOmciMsg->content[13], &tempBuf, sizeof(UINT16));
        pOmciMsg->content[12] = PPTP_FTTR_P2MP_PORT_TEST_SELF_TEST_RESULT_TEMPERATURE;

    }

    // send back the response
    ret = OMCI_SendMsg(OMCI_APPL,
                        OMCI_TX_OMCI_MSG,
                        OMCI_MSG_PRI_NORMAL,
                        pOmciMsg,
                        sizeof(omci_msg_norm_t));
    if (GOS_OK != ret)
    {
        OMCI_LOG(OMCI_LOG_LEVEL_ERR, "Unable to send out test result: %s",
            MIB_GetTableName(tableIndex));
    }
    // free allocated memory before leaving
    free(pData);
    return ret;
    

}



GOS_ERROR_CODE mibTable_init(MIB_TABLE_INDEX tableId)
{
    UINT8 proprietary_mib_cb_bitmask = 0;
    UINT8 isIgnore = 0;

    if(GOS_OK == omci_ignore_mib_table_check(OMCI_ME_CLASS_PPTP_FTTR_P2MP_PORT, OMCI_ME_CLASS_SUB_DEFAULT, &isIgnore))
    {
        if(isIgnore)
        {
            OMCI_PRINT("Ignore classId:%d", OMCI_ME_CLASS_MAIN_FTTR_UNIT);
            return GOS_FAIL;
        }
    }

    gMibPptpFttrP2mpPortTableInfo.Name = "PptpFttrP2mpPort";
    gMibPptpFttrP2mpPortTableInfo.ShortName = "PptpFttrP2mpPort";
    gMibPptpFttrP2mpPortTableInfo.Desc = "PPTP FTTR P2MP Port";
    gMibPptpFttrP2mpPortTableInfo.ClassId = (UINT32)(OMCI_ME_CLASS_PPTP_FTTR_P2MP_PORT);
    gMibPptpFttrP2mpPortTableInfo.InitType = (UINT32)(OMCI_ME_INIT_TYPE_ONU);
    gMibPptpFttrP2mpPortTableInfo.StdType = (UINT32)(OMCI_ME_TYPE_PROPRIETARY);
    gMibPptpFttrP2mpPortTableInfo.ActionType = (UINT32)(OMCI_ME_ACTION_SET | OMCI_ME_ACTION_GET | OMCI_ME_ACTION_TEST);
    gMibPptpFttrP2mpPortTableInfo.pAttributes = &(gMibPptpFttrP2mpPortAttrInfo[0]);
    gMibPptpFttrP2mpPortTableInfo.attrNum = MIB_TABLE_PPTP_FTTR_P2MP_PORT_ATTR_NUM;
    gMibPptpFttrP2mpPortTableInfo.entrySize = sizeof(MIB_TABLE_PPTP_FTTR_P2MP_PORT_T);
    gMibPptpFttrP2mpPortTableInfo.pDefaultRow = &gMibPortFttrP2mpPortDefRow;
    
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Name = "EntityID";
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Name = "AdminState";
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Name = "OpState";
              
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Entity ID";
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Administrative state";
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Operational state";

    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_UINT16;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_UINT8;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_UINT8;
           
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Len = 2;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Len = 1;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].Len = 1;

    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = TRUE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = FALSE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = FALSE;
           
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;

    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_HEX;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_DEC;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_DEC;
           
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ | OMCI_ME_ATTR_ACCESS_WRITE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ;

    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;

    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = OMCI_ME_ATTR_TYPE_MANDATORY;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_ADMINSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = OMCI_ME_ATTR_TYPE_MANDATORY;
    gMibPptpFttrP2mpPortAttrInfo[MIB_TABLE_PPTP_FTTR_P2MP_PORT_OPSTATE_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = OMCI_ME_ATTR_TYPE_MANDATORY;
      

    memset(&gMibPortFttrP2mpPortDefRow, 0x00, sizeof(gMibPortFttrP2mpPortDefRow));


    memset(&gMibPptpFttrP2mpPortOper, 0x0, sizeof(MIB_TABLE_OPER_T));
    gMibPptpFttrP2mpPortOper.meOperDrvCfg = omci_mib_pptp_fttr_p2mp_port_drv_cfg;
    gMibPptpFttrP2mpPortOper.meOperConnCheck = NULL;
    gMibPptpFttrP2mpPortOper.meOperDump = omci_mib_oper_dump_default_handler;
    gMibPptpFttrP2mpPortOper.meOperConnCfg = NULL;
    gMibPptpFttrP2mpPortOper.meOperAlarmHandler = omci_mib_pptp_fttr_p2mp_port_alarm_handler;
    gMibPptpFttrP2mpPortOper.meOperTestHandler = pptp_fttr_p2mp_port_test_handler;
    gMibPptpFttrP2mpPortOper.meOperCb[PROPRIETARY_MIB_CB_RESET] = omci_mib_pptp_fttr_p2mp_port_reset;

    MIB_TABLE_PPTP_FTTR_P2MP_PORT_INDEX = tableId;
    MIB_InfoRegister(tableId,&gMibPptpFttrP2mpPortTableInfo,&gMibPptpFttrP2mpPortOper);

    proprietary_mib_cb_bitmask = (1 << PROPRIETARY_MIB_CB_RESET);
    MIB_Proprietary_Reg(tableId, proprietary_mib_cb_bitmask);

    return GOS_OK;
}
